package scatter.comment.rest.subject.service.impl;

import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.util.Assert;
import scatter.comment.pojo.subject.param.CommentSubjectStarCancelStarParam;
import scatter.comment.pojo.subject.param.CommentSubjectStarAddStarParam;
import scatter.comment.pojo.subject.po.CommentSubject;
import scatter.comment.pojo.subject.po.CommentSubjectStar;
import scatter.comment.rest.subject.mapper.CommentSubjectStarMapper;
import scatter.comment.rest.subject.mapstruct.CommentSubjectStarMapStruct;
import scatter.comment.rest.subject.service.ICommentSubjectService;
import scatter.comment.rest.subject.service.ICommentSubjectStarService;
import scatter.common.pojo.form.BasePageQueryForm;
import scatter.common.rest.service.IBaseAddUpdateQueryFormServiceImpl;
import org.springframework.stereotype.Service;
import scatter.comment.pojo.subject.form.CommentSubjectStarAddForm;
import scatter.comment.pojo.subject.form.CommentSubjectStarUpdateForm;
import scatter.comment.pojo.subject.form.CommentSubjectStarPageQueryForm;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;

/**
 * <p>
 * 主体评论点赞表 服务实现类
 * </p>
 *
 * @author yw
 * @since 2021-02-09
 */
@Slf4j
@Service
@Transactional
public class CommentSubjectStarServiceImpl extends IBaseAddUpdateQueryFormServiceImpl<CommentSubjectStarMapper, CommentSubjectStar, CommentSubjectStarAddForm, CommentSubjectStarUpdateForm, CommentSubjectStarPageQueryForm> implements ICommentSubjectStarService {

    @Qualifier("commonDbTaskExecutor")
    @Autowired
    private ExecutorService executorService;

    @Lazy
    @Autowired
    private ICommentSubjectService iCommentSubjectService;


    @Override
    public void preAdd(CommentSubjectStarAddForm addForm,CommentSubjectStar po) {
        super.preAdd(addForm,po);

    }

    @Override
    public void preUpdate(CommentSubjectStarUpdateForm updateForm,CommentSubjectStar po) {
        super.preUpdate(updateForm,po);

    }



    /**
     * 异步处理添加，该方法永远返回true
     * @param addStartParam
     * @return
     */
    @Override
    public CommentSubjectStar addStar(CommentSubjectStarAddStarParam addStartParam) {
        CommentSubjectStar commentSubjectStar = CommentSubjectStarMapStruct.INSTANCE.addStartParamToPo(addStartParam);
        commentSubjectStar.setTimeAt(LocalDateTime.now());
        // 楼层默认设置为1
        commentSubjectStar.setFloor(Optional.ofNullable(addStartParam.getFloor()).orElse(1));
        log.info("开始添加一个点赞,commentSubjectId={},userId={}",addStartParam.getCommentSubjectId(),addStartParam.getOwnerUserId());
        boolean save = save(commentSubjectStar);
        if (save) {
            // 添加成功后，点赞数加 1
            iCommentSubjectService.plusForColumnById(addStartParam.getCommentSubjectId(), CommentSubject::getStarCount,1);


            // 如果楼层没传，修正楼层
            if (addStartParam.getFloor() == null) {
                CommentSubject byId = iCommentSubjectService.getById(addStartParam.getCommentSubjectId());
                // 1 可能是默认添加的，这里不再处理
                if (byId.getFloor() > 1) {
                    LambdaUpdateWrapper<CommentSubjectStar> subjectStarLambdaUpdateWrapper = Wrappers.<CommentSubjectStar>update().lambda().eq(CommentSubjectStar::getId, commentSubjectStar.getId()).set(CommentSubjectStar::getFloor, byId.getStarCount());
                    update(subjectStarLambdaUpdateWrapper);
                }
            }

        }else {
            log.error("添加一个点赞失败，因为在保存数据时返回false，这将导致评论主体点赞数不会加1");
        }

        log.info("添加一个点赞结束,commentSubjectId={},userId={},id={}",addStartParam.getCommentSubjectId(),addStartParam.getOwnerUserId(),commentSubjectStar.getId());

        return commentSubjectStar;
    }

    /**
     * 异步处理取消，该方法永远返回 true
     * @param cancelStarParam
     * @return
     */
    @Override
    public boolean cancelStar(CommentSubjectStarCancelStarParam cancelStarParam) {
        executorService.execute(()->{
            log.info("开始取消点赞,commentSubjectId={},userId={}",cancelStarParam.getCommentSubjectId(),cancelStarParam.getOwnerUserId());
            boolean remove = remove(Wrappers.<CommentSubjectStar>lambdaQuery()
                    .eq(CommentSubjectStar::getCommentSubjectId, cancelStarParam.getCommentSubjectId())
                    .eq(CommentSubjectStar::getOwnerUserId, cancelStarParam.getOwnerUserId())
            );
            if (remove) {
                // 取消成功后，点赞数减 1
                iCommentSubjectService.plusForColumnById(cancelStarParam.getCommentSubjectId(), CommentSubject::getStarCount,-1);
            }else {
                log.error("取消点赞失败，因为删除点赞数据返回false，这将导致评论数据的点赞数不会减1");
            }

            log.info("取消点赞结束,commentSubjectId={},userId={}",cancelStarParam.getCommentSubjectId(),cancelStarParam.getOwnerUserId());
        });
        return true;
    }

    @Override
    public Map<String, Page<CommentSubjectStar>> listLatestStarForPerCommentSubject(List<String> commentSubjectIds, Integer count) {
        Assert.notEmpty(commentSubjectIds,"commentSubjectIds 不能为空");
        Assert.notNull(count,"count 不能为空");


        Map<String,Page<CommentSubjectStar>> result = new HashMap<>();

        CompletableFuture[] completableFutures = commentSubjectIds.stream().map(commentSubjectId -> CompletableFuture.supplyAsync(() -> {
            // 我嚓，这个 page 不能提出来，否则得到的数据会是一样的
            Page page = convertPage(new BasePageQueryForm().setCurrent(1L).setSize(Integer.toUnsignedLong(count)));
            page.setSearchCount(false);
            Page page1 = page(page, Wrappers.<CommentSubjectStar>lambdaQuery().eq(CommentSubjectStar::getCommentSubjectId, commentSubjectId).orderByDesc(CommentSubjectStar::getTimeAt));
            return page1;
        }, executorService).whenComplete((r,e)->{result.put(commentSubjectId, (Page<CommentSubjectStar>)r);})).toArray(CompletableFuture[]::new);
        CompletableFuture.allOf(completableFutures).join();
        return result;
    }
}
